# -*- coding: utf-8 -*-
# -------------------------------
# @PyCharm：PyCharm 2023.1.3 (Community Edition)
# @Python：Python 3.8.10
# @时间：2024/11/23 20:49
# -------------------------------

import hashlib
import random
import sys
from os import getcwd

from fastapi import FastAPI, responses, Cookie, Form, Depends
from fastapi.staticfiles import StaticFiles
from typing import Optional, List
import uvicorn
from pydantic import BaseModel

sys.path.append(f"{getcwd()}\coding")
from coding import db

class Session(BaseModel):
    session_id:str

async def perssion_verify(session_id:Optional[str] = Cookie(None)):
    """
    :param session_id: 用户登录之后，服务端为用户分配的随机会话编号，范围为1~10000
    :return: 返回右两种情况，一种是返回空，意味着当前客户端并没有和服务器建立过会话
             另一种是返回一个字符串，字符串中包含当前用户所拥有的权限
    """
    if not session_id:
        return
    data = db_project.read_staffs_from_sess(session_id)
    if not data:
        return
    permission = data[4].split(",")
    return permission

app = FastAPI()

app.mount("/static", StaticFiles(directory="data"), name="static")

@app.get('/', response_class=responses.HTMLResponse)
async def get_index():
    """
    :return: 返回首页
    """
    with open("data/html/index.html") as f:
        return f.read()

@app.get("/login", response_class=responses.HTMLResponse)
async def login_page():
    """
    :return: 返回登录页面
    """
    with open("data/html/login.html") as f:
        return f.read()

@app.get("/register", response_class=responses.HTMLResponse)
async def register_page():
    """
    :return: 返回注册页面
    """
    with open("data/html/register.html") as f:
        return f.read()

@app.get('/chart', response_class=responses.HTMLResponse)
async def get_chart(depend:Optional[List[str]] = Depends(perssion_verify)):
    """
    :param depend: 权限验证的返回结果，为空或权限列表
    :return: 返回登录页面的重定向，图表页面，或者是404错误页面
    """
    if not depend:
        return responses.RedirectResponse("/login")
    if "3" in depend:
        with open("data/html/chart.html") as f:
            return f.read()
    with open(f"data/html/404.html") as f:
        return f.read()


@app.get('/excel', response_class=responses.HTMLResponse)
async def get_excel(q:str = "device", depend:Optional[List[str]] = Depends(perssion_verify)):
    """
    :param q: 区分表格的种类（因为三种表格的请求集中到了同一个接口）
    :param depend: 权限验证的返回结果，为空或权限列表
    :return: 返回登录页面的重定向，图表页面，或者是404错误页面
    """
    if not depend:
        return responses.RedirectResponse("/login")
    dic = {"device": "1", "alarm": "2", "staff": "4"}
    if dic[q] in depend:
        with open(f"data/html/{q}_excel.html") as f:
            return f.read()
    with open(f"data/html/404.html") as f:
        return f.read()

@app.post("/api/login")
async def login(account: str = Form(...), password: str = Form(...)):
    """
    :param account: 账号，可以是用户名，手机号或电子邮箱
    :param password: 密码，明文密码，未经客户端加密，会再写入时加密
    :return: 返回登录页面的重定向或者首页的重定向
    """
    flag = 0
    datas = db_project.read_data("staffs")
    for data in datas:
        if account not in data:
            continue
        print("账号验证成功")
        md5_pwd = hashlib.new('md5', password.encode()).hexdigest()
        if md5_pwd == data[2]:
            flag = 1
            staff_id = data[0]
            break
    if flag == 1:
        response = responses.RedirectResponse('/', status_code=303)
        data = db_project.read_data("session")
        values = [i[2] for i in data]
        while True:
            value = random.randint(1, 10000)
            if value not in values:
                break
        response.set_cookie(key='session_id', value=str(value))
        dic = {'staff_id': staff_id, 'value': value}
        db_project.write_data(dic, 'session')
        return response
    return responses.RedirectResponse("/login", status_code=303)



@app.post("/api/register")
async def register(
        username: str = Form(...),
        password: str = Form(...),
        phonenumber: str = Form(...),
        email: str = Form(...),
):
    """
    :param username: 用户名
    :param password: 密码
    :param phonenumber: 手机号
    :param email: 电子邮箱
    :return: 注册成功返回重定向到登录页面，注册失败返回重定向到注册页面
    """
    staff_dic = {"name": username,
                'password': password,
                'phonenumber': phonenumber,
                'email': email}
    datas = db_project.read_data("staffs")
    for data in datas:
        if username in data:
            break
        if phonenumber in data:
            break
        if email in data:
            break
    else:
        staff_dic['password'] = hashlib.new('md5', staff_dic['password'].encode()).hexdigest()
        db_project.write_data(staff_dic, 'staffs')
        return responses.RedirectResponse("/login", status_code=303)
    return responses.RedirectResponse("/register", status_code=303)

@app.get("/api/excel-data", response_class=responses.JSONResponse)
async def get_excel_data(q:str):
    """
    :param q: 区分表格的种类（因为三种表格的请求集中到了同一个接口）
    :return: 以json的格式返回对应的表格数据
    """
    if q == "staff":
        return db_project.read_staffs_data()
    dic = {"device": "iron_define_data", "alarm": "alarm_data", "staff": "staffs"}
    return db_project.read_data(dic[q])

@app.get('/api/chart-data', response_class=responses.JSONResponse)
async def get_chart_data():
    """
    :return: 以json的格式返回iron_define_data表中的数据
    """
    li = db_project.read_last_data("iron_define_data")
    return li

@app.get('/api/staff-data', response_class=responses.JSONResponse)
async def get_staff_data(session_id:Optional[str] = Cookie(None)):
    """
    :param session_id: 用户登录之后，服务端为用户分配的随机会话编号，范围为1~10000
    :return: 以json的格式返回seession_id对应在staffs表中的数据
    """
    if not session_id:
        return responses.RedirectResponse("/login")
    li = db_project.read_staffs_from_sess(session_id)
    return li

@app.post("/api/del-session")
async def del_session(session:Session):
    """
    :param session: 只包含一个键session_id的键值对，用作删除的条件
    :return: 返回空值，只是通知服务端通知数据库删除相关记录
    """
    session_id = session.session_id
    db_project.del_session(session_id)

@app.post("/api/alarm-data-deal")
async def del_session(session_id:Optional[str] = Cookie(None),
                      requ_alarm_id: str = Form(None),
                      sub_alarm_id: str = Form(None)):
    """
    :param session_id: 用户登录之后，服务端为用户分配的随机会话编号，范围为1~10000
    :param requ_alarm_id: 异常数据的序号，用以登记维修事务开始着手处理
    :param sub_alarm_id: 异常数据的序号，用以登记维修事务已完成
    :return:
    """
    if requ_alarm_id:
        data = db_project.read_staffs_from_sess(session_id)
        staff_id = data[0]
        db_project.update_alarm_from_id(requ_alarm_id, staff_id)
    if sub_alarm_id:
        db_project.update_alarm_from_id(sub_alarm_id)

    return responses.RedirectResponse("/excel?q=alarm", status_code=303)

@app.post("/api/staff-data-deal")
async def del_session(username:str = Form(None),
                      password:str = Form(None),
                      phonenumber:str = Form(None),
                      email:str = Form(None),
                      job_id:str = Form(None),
                      assign_staff_id:str = Form(None),
                      assign_job_id: str = Form(None),
                      del_staff_id:str = Form(None)):
    """
    :param username: 用户名
    :param password: 密码
    :param phonenumber: 手机号
    :param email: 电子邮箱
    :param job_id: 人员职位编号，用以注册用户
    :param assign_staff_id: 人员编号，用以分配职位
    :param assign_job_id: 人员职位编号，用以分配职位
    :param del_staff_id: 人员编号，用以删除人员信息
    :return: 异常数据页的重定向
    """
    dic1 = {"name": username,
            "password":hashlib.new('md5', password.encode()).hexdigest(),
            "phonenumber":phonenumber,
            "email":email,
            "job_id":job_id}
    if all([*dic1.values()][:len(dic1)-1]):
        db_project.write_data(dic1, "staffs")
    if all([assign_staff_id, assign_job_id]):
        db_project.assign_job_from_id(assign_staff_id, assign_job_id)
    if del_staff_id:
        db_project.del_staff_from_id((del_staff_id))
    return responses.RedirectResponse("/excel?q=staff", status_code=303)



if __name__ == '__main__':
    db_project = db.DB()
    uvicorn.run(app=app, port=8880)

